<template>
  <el-form
    ref="form"
    :inline="inline"
    :model="newData"
    :rules="validateRules"
    :style="formerStyle"
    :label-width="labelWidth"
    :class="overflow ? 'former' : 'former-overflow-false'"
  >
    <!-- 支持多维数组的行列布局 -->
    <el-row v-for="(row, rowIndex) in fields" :key="`row-${rowIndex}`" :gutter="16">
      <el-col v-for="widget in row" :key="widget.field" :span="getColumnSpan(row.length, widget)">
        <el-form-item
          :class="{
            hidden: widget.hidden ?? false,
            'is-required': widget.required || hasRequiredRule(widget),
            'increase-margin-bottom': widget.hasOwnProperty('tip'),
          }"
          :error="validate.err(widget.field)"
          :label="widget.label"
          :placeholder="widget.placeholder"
          :prop="widget.field"
        >
          <component
            :is="elComponents[widget.type].name"
            :ref="(el: refItem) => setRefMap(el, widget.field)"
            v-model="newData[widget.field]"
            v-bind="getBindData(elComponents[widget.type].props, widget)"
            @on-uploaded="onUploaded"
          />
          <div
            v-if="widget.hasOwnProperty('tip') && validate.err(widget.field) === null"
            class="form-item-help-tip"
          >
            {{ widget.tip }}
          </div>
        </el-form-item>
      </el-col>
    </el-row>

    <div :class="{ 'former-footer-background': footerBackground }" class="former-footer">
      <el-button v-if="cancelButton" @click="handlerCancel">取消</el-button>
      <slot name="button"></slot>
      <el-button :loading="loading" type="primary" @click="handlerConfirm">
        <span v-if="!loading">{{ button }}</span>
        <span v-else>Loading ...</span>
      </el-button>
    </div>
  </el-form>
</template>

<script setup lang="ts">
  import type { FormInstance } from 'element-plus'

  import type { ComponentPublicInstance } from 'vue'

  import Validation from '#/utils/validation'

  import elComponents from './config'

  type refItem = ComponentPublicInstance | Element | null

  defineOptions({
    name: 'Former',
  })

  const props = withDefaults(
    defineProps<{
      button?: string
      cancelButton?: boolean
      data: Record<string, any>
      fields: FormField[][]
      footerBackground?: boolean
      inline?: boolean
      labelWidth?: string
      loading: boolean
      maxHeight?: string
      overflow?: boolean
      validate: typeof Validation
    }>(),
    {
      maxHeight: '60vh',
      fields: () => [],
      overflow: true,
      inline: false,
      loading: false,
      cancelButton: true,
      button: '确定',
      labelWidth: '140px',
      footerBackground: true,
    }
  )
  const emits = defineEmits<{
    (e: 'on-confirmed', data: any): void
    (e: 'on-closed'): void
  }>()

  const { proxy } = getCurrentInstance()!
  const form = ref<FormInstance>()
  const newData = ref<Record<string, any>>({})
  const validateRules = ref({})
  const formerStyle = computed(() => ({ maxHeight: props.maxHeight }))
  const isCreate = computed(() => JSON.stringify(props.data) === '{}')
  const refMap = ref<Record<string, refItem>>({})

  // 获取所有字段（扁平化二维数组）
  const getAllFields = (fields: FormField[][]): FormField[] => {
    return fields.flat()
  }

  // 计算列的span值（基于24栅格系统）
  const getColumnSpan = (rowLength: number, widget: FormField): number => {
    // 如果字段有自定义span，使用自定义值
    if (widget.span !== null && widget.span !== undefined) {
      return widget.span
    }

    // 否则平均分配24栅格
    return Math.floor(24 / rowLength)
  }

  // 检查字段是否有必填规则
  const hasRequiredRule = (widget: FormField): boolean => {
    if (!widget.rules || !Array.isArray(widget.rules)) return widget.required || false
    return widget.rules.some((rule) => rule.rule === 'required')
  }

  // 处理验证规则
  const processValidationRules = (fields: FormField[][]) => {
    const rules: Record<string, any[]> = {}
    const allFields = getAllFields(fields)

    allFields.forEach((field) => {
      if (field.rules && Array.isArray(field.rules)) {
        // 处理新的rules数组格式
        const fieldRules: any[] = []

        field.rules.forEach((ruleItem) => {
          const rule: any = {
            message: ruleItem.msg || `${field.label || field.field}格式不正确`,
            trigger: 'blur',
          }

          // 解析不同类型的验证规则
          switch (ruleItem.rule) {
            case 'email': {
              rule.type = 'email'
              break
            }
            case 'nullable': {
              // nullable规则通常表示可以为空，不需要特殊处理
              break
            }
            case 'number': {
              rule.type = 'number'
              break
            }
            case 'required': {
              rule.required = true
              break
            }
            case 'string': {
              rule.type = 'string'
              break
            }
            default: {
              // 处理带参数的规则，如 max:8, min:3 等
              if (ruleItem.rule.includes(':')) {
                const [ruleName, ruleValue] = ruleItem.rule.split(':')
                switch (ruleName) {
                  case 'max': {
                    if (field.type === 'input' || field.type === 'textarea') {
                      rule.max = Number.parseInt(ruleValue)
                    }
                    break
                  }
                  case 'min': {
                    if (field.type === 'input' || field.type === 'textarea') {
                      rule.min = Number.parseInt(ruleValue)
                    }
                    break
                  }
                  case 'regex': {
                    rule.pattern = new RegExp(ruleValue)
                    break
                  }
                }
              }
              break
            }
          }

          // 只添加有效的规则
          if (Object.keys(rule).length > 2) {
            // message 和 trigger 之外还有其他属性
            fieldRules.push(rule)
          }
        })

        if (fieldRules.length > 0) {
          rules[field.field] = fieldRules
        }
      } else if (field.required) {
        // 兼容原有的required字段
        rules[field.field] = [
          {
            required: true,
            message: `${field.label || field.field}不能为空`,
            trigger: 'blur',
          },
        ]
      }
    })

    return rules
  }

  watch(
    () => props.fields,
    (newV) => {
      const allFields = getAllFields(newV)

      // 处理验证规则
      validateRules.value = processValidationRules(newV)

      if (isCreate.value) {
        allFields.forEach((item) => {
          newData.value[item.field] = ''
          if (item.default !== undefined) {
            newData.value[item.field] = item.default
          }

          // 对上次上传的图片做预览的清理
          if (
            (item.type === 'upload-image' || item.type == 'upload-file') &&
            refMap.value[`${item.field}`]
          ) {
            const ref = refMap.value[`${item.field}`] as any
            ref?.resetData?.()
          }
        })
      } else {
        allFields.forEach((item) => {
          newData.value[item.field] = props.data[item.field] ?? ''

          if (item.type === 'cascader') {
            newData.value[item.field] = item.default // 可以重置控件的值，提交时又格式化回到 model 的值
          }
        })
      }
    },
    {
      immediate: true, // 立即执行以初始化验证规则
      deep: true,
    }
  )

  const setRefMap = (el: refItem, field: string) => {
    if (el) refMap.value[`${field}`] = el
  }

  // TODO: 为什么在窗口关闭时，还会调用一个 getBindData ???
  const getBindData = (config: Record<string, any>, widget: FormField) => {
    const append: Record<string, any> = { isCreate: isCreate.value } // , size: widget.size ?? 'default'
    if (widget.type == 'upload-image' || widget.type == 'upload-file') {
      // 不可以重置控件的值，所以新增一个属性，比如：在不修改时还是 model 的原始值
      append.preview = props.data[`${widget.field}_url`] ?? ''
    }

    // TODO: 为何这么写 radio 组件的 options 会重复显示
    // widget 中的所有属性不一定都需要 v-bind 给子组件
    // for (let key in widget) {
    //   if (['width', 'height', 'options'].includes(key)) {
    //     if (!append.hasOwnProperty(key)) {
    //       append[key] = widget[key]
    //     }
    //   }
    // }
    // return { ...config, ...append }
    // console.log('Former-log getBindData append:', append)

    return { ...widget, ...config, ...append }
  }

  // TODO: array 是 false， 但values会返回数组，Cascader类型是string[] | number[] | any，不选择的时候，values 返回 null
  // 初始化时设置默认值为 '' 就不会返回 null
  const formatCascader = (values: any, multiple?: boolean, array?: boolean) => {
    // if (values === null) {
    //   return []
    // }
    // 返回数组格式
    if (array) {
      return values == '' ? [] : values
    }

    if (!multiple) {
      return values == '' ? '' : values[values.length - 1]
    }

    if (values == '' || values.length === 0) {
      return []
    }

    const res: string[] = []
    values.forEach((item: any) => {
      res.push(item[item.length - 1]) // 返回多选的最后一项值
    })

    return res
  }
  const handlerCancel = () => {
    proxy
      ?.$confirm('确定关闭吗？', '温馨提示', { type: 'warning' })
      .then(() => {
        emits('on-closed')
      })
      .catch(() => {
        // 用户取消操作
      })
  }

  const onUploaded = (target_name: string, newV: [] | null | string) => {
    // console.log(newV, self_name, target_name)
    newData.value[target_name] = newV
  }

  const handlerConfirm = () => {
    // console.log('Former-log handlerConfirm: ', newData.value)
    form.value?.validate((valid) => {
      if (valid) {
        const res: Record<string, any> = {}
        const allFields = getAllFields(props.fields)
        allFields.forEach((item) => {
          // console.log('Former-log handlerConfirm item: ' + item)
          res[item.field] =
            item.type === 'cascader'
              ? formatCascader(newData.value[item.field], item.multiple, item.array)
              : newData.value[item.field]
        })
        // console.log('Former-log handlerConfirm res: ' + res)
        const validation = props.validate as any
        validation?.clean?.() // 解决 validate 和 error 一起用时，后端的 error 信息不显示
        emits('on-confirmed', res)
      }
    })
  }

  defineExpose({
    resetFields: () => {
      form.value?.resetFields()
    },
  })
</script>

<style scoped lang="scss">
  .increase-margin-bottom {
    @apply mb-30px;
  }

  .former {
    @apply py-10px pr-60px min-h-120px overflow-y-auto overflow-x-hidden;
  }

  .former-overflow-false {
    @apply py-10px px-60px min-h--120px;
  }

  .form-item-help-tip {
    @apply top-100% left-10px font-s-13px line-height-1 pt-10px color-color-place absolute;
  }

  .hidden {
    @apply display-none;
  }

  .former-footer {
    @apply bottom-10px py-15px pl-15px pr-60px rd-b-4px absolute left-0 right-0 m-0 text-right;
  }

  .former-footer-background {
    @apply bg-color-f4f7fa bottom-0;
  }
</style>
